package com.winning.pa.ws.util;

import java.io.ByteArrayOutputStream;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CharsetEncoder;
import java.nio.charset.StandardCharsets;
import java.security.Security;

import javax.crypto.Cipher;
import javax.crypto.CipherOutputStream;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

import org.bouncycastle.jce.provider.BouncyCastleProvider;  

public class AESUtils {
    
    static {
    	Security.setProperty("crypto.policy", "unlimited");
        Security.addProvider(new BouncyCastleProvider());
    }
	
    public static void main(String[] args) throws Exception {
    	String str = "0688867FE6F0224857FBD58C01F2654EC6BF31B5D252212B6D85734DD296E7C3EDD30DC2CEF62F404629A02598A659FDB0C30904EF9DCB04244EF7BCB99F18A05A37AC5B027805A27EE8B50BC43A62408B2ACA642985892B686A0E3F5BB925C8651F28CD82D485B34F028DB68FB1795F6DA87244D1D40CE11438D98215391EB5890B4F80925246A36354DE841A5026F8306B025BBC3CAEC8E628460576159CF65D177A76C6DCC2E068B825FB3E23CB69D581AB005757583FDDF6AA7B0348C0BA27C1FC84D925BD0710770030D0422A66071015C83367134FCC8D2A42457BD1235C89C89EC551489DF7E1B78E8A1656F28AB5BD4EF06BDE638AF7089FF96FC3E4E3C5F2EE28CFC43FA5970291D42E4777FF4A4FE7B4C48033E0E22EC2F17C91C7C8A3968F6A7FD7FF22C1D41F80E2AAB6CD54F266F182240990ABC0EC8F223D26CCC6B670C1655B21F83A525222C5AF2C203B1359E081C84CA12A00D8FD72260E3B25B7D0CC5E188EB2F7A0062B45702235197BDA74453F0824744E7A354754D77EB5D720D0096A70425F5604B868FF22ADBB09408CA8E33CC7D8D9F36BAF4E53A17EB5921E8316A0362EA4D4ACB9A8EC03D26CAEE536E9B2B0A5A34FED2C251F602C51F92EB8EBC5FB6CE01C71B96E84EA8C41FE9CDC10C7F16933E1C5057BBA03715E14646BD4F566153D0C49804CEA2C4D06AA9905B3165FF990164B32517500C097A6B1C3C58310D60F877348E814B2BBF371A1DFFA7230E2F3EEF88547AB07AB93997B329664F86478145183279CC918B2055CCD6EEFFFD2C88489F88B3176820BF28546F1606A425668647CD3E1B8A1155FA5B3CE8B403D273A1392F179B23B5D3399943AA75F2C49CCBE2CF7F269011A42F6585502087384522877A04582A0D494EBAB101F99C3B5DD810CF2C34FF81DC21740DEABE0338767BDBBE6459F86E08F9E885CC34166EB21277FAD43686DEDC3F08CE05F3EC01AEB7551DA6A3D8A599F9EF83552D0362AA33418247E0B26B2FAE122E78AF6555E991F5E8DD2A0E07F1CF570B9C02BD47BF435743DC7A83A9413C995B7D0279648491FB19C1F2E92CDB763662E2402A2563F4E231876E0CFDC3741BB1AA86F126722954EE0683DEDE0C1B40E0E87C88EACE6BA60DAE558E12D6630D413C18691A9CA05D0714BF5DE29ED5C12DB7D98AD4EAA7948ECD9193B625DD38CE564DD579F0F2829F3D24E82CF9F5EED1A7EFB27D0F538492C20D37E98B922F6DFB497D83DB055D1EDD7E78130F406F5B5AC5F1507CC222E464BF4830F27415243A60542E85A67F12DCE2FB450346F0C74F9171706F639A0E1446DA8D6731E3960A02CF84072976064291DE98AF6F007558ED565685AD70E774837C2EE4968DD336FA645593CBE0873CF39A5831046352BED387EC44F60CF158B76736A4E6F54A6BBE5B429F7C5E620CFC36A756A812E32E06532542BA25F818F21D714B7CDC9E89A0F27AFDD9C4F3A1FD9A985909A964F2C6372786DDD62A53935651816C3ADAE0E2BCEBB42E82650FC5DF96F5FB84801206F0FA2FF10FDAFCA";  
        
    	String str1 = "Hello AES! 你好 AES";

    	// 获取系统默认字符集  
        Charset defaultCharset = Charset.defaultCharset();  
        System.out.println("系统默认字符集：" + defaultCharset);  
  
        // 获取系统默认字符集的编码规则  
        CharsetEncoder encoder = defaultCharset.newEncoder();  
        System.out.println("系统默认字符集编码规则：" + encoder.charset().name());  
  
        // 获取系统默认字符集的解码规则  
        CharsetDecoder decoder = defaultCharset.newDecoder();  
        System.out.println("系统默认字符集解码规则：" + decoder.charset().name()); 
    	
//    	System.out.println(decrypt(str, "zhyl4cxrh"));  
    	System.out.println((decrypt(encrypt(str1, "zhyl4cxrh"), "zhyl4cxrh")));  
    }
    
    public static String decrypt(String text, String key) {  
        try { 
        	String IV = text.substring(0, 32);  
        	text = text.substring(32);
        	
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding", "BC");  
            SecretKeySpec keySpec = new SecretKeySpec(GetLegalKey(cipher, key), "AES");  
//            IvParameterSpec ivSpec = new IvParameterSpec(StringToBytes("0688867FE6F0224857FBD58C01F2654E")); 
            IvParameterSpec ivSpec = new IvParameterSpec(StringToBytes(IV)); 
            cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);  
            byte[] encrypted = StringToBytes(text);  
            byte[] decrypted = cipher.doFinal(encrypted);
            String originalString = new String(decrypted, "GBK");
            return originalString.toString();
        } catch (Exception e) {  
            e.printStackTrace();  
            return null;  
        }  
    }
    
    public static String encrypt(String text, String key) throws Exception {  
    	Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding", "BC");  
      
    	SecretKeySpec keySpec = new SecretKeySpec(GetLegalKey(cipher, key), "AES");  
    	
        byte[] iv;  
        synchronized (cipher) {  
            cipher.init(Cipher.ENCRYPT_MODE, keySpec);  
            iv = cipher.getIV();  
        }  
      
        byte[] buffer;  
        try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {  
            try (CipherOutputStream cos = new CipherOutputStream(baos, cipher)) {  
                buffer = text.getBytes("GBK");  
                cos.write(buffer, 0, buffer.length);  
            }  
            buffer = baos.toByteArray();  
        }  
      
        return BytesToString(iv) + BytesToString(buffer);  
    }
    
    private static byte[] GetLegalKey(Cipher cipher, String key) throws Exception {  
        byte[] source = key.getBytes(StandardCharsets.US_ASCII);  
        byte[] dest = new byte[32];
        System.arraycopy(source, 0, dest, 0, Math.min(source.length, dest.length));  
        return dest;  
    }
    
    private static byte[] StringToBytes(String str)
    {
        byte[] bytes = new byte[str.length() / 2];
        for (int i = 0; i < bytes.length; i++)
        {
            bytes[i] = (byte)Integer.parseInt(str.substring(i * 2, (i * 2 + 2)), 16);

        }

        return bytes;
    }
    
    private static String BytesToString(byte[] bytes)
    {
        StringBuilder sb = new StringBuilder(bytes.length * 2);
        for (byte b : bytes)
        {
            sb.append(String.format("%02X", b));  
        }

        return sb.toString();
    }
    

}
